package justweb

import (
	"fmt"
	"net/http"
	"strings"
)

// 树结构路由  map[Method]Tree

// 目前这个版本增加通配符*匹配、路径参数:param、正则:reg()、支持复杂匹配，支持扩展路由

// 树的结构
type BaseOnTree struct {
	// tree map[string]*treenode
	tree map[string]BaseNode
}

// var _ http.Handler = &BaseOnTree{}
// 重构之后，已经没有实现http.Handler接口了——因为方法参数变了，所以下面的ServeHTTP只是逻辑上的处理

var httpMethod = [4]string{
	http.MethodGet,
	http.MethodPost,
	http.MethodPut,
	http.MethodDelete,
}

// 这个是路由接口的ServeHTTP方法，整个调用过程就是在创建的Server的时候，把这里的ServerHTTP当做链头，
// 随后插入中间件就逐渐往外包一层层。在请求过来的时候，首先到Server的ServeHTTP方法，那里封装请求，然后
// 将请求作为参数传入责任链。经过一层层中间件之后，到达这里的ServeHTTP。
func (t *BaseOnTree) ServeHTTP(c *Context) {
	// 查找路由树，处理请求
	if _, ok := t.tree[c.R.Method]; !ok {
		c.W.WriteHeader(http.StatusNotFound)
		c.W.Write([]byte("not found"))
		return
	}
	node := t.tree[c.R.Method].(*treenode)

	// 重构一下，因为针对参数处理的逻辑，放在寻找路由中，比较类似一个整体
	// paths := strings.Split(strings.Trim(c.R.URL.Path, "/"), "/")

	handfunc, ok := node.FindRouter(c.R.URL.Path, c)
	if !ok {
		c.W.WriteHeader(http.StatusNotFound)
		c.W.Write([]byte("not found"))
		return
	}
	handfunc(c)
}

// 路由注册，将路径插入到树里
func (t *BaseOnTree) Route(method string, pattern string, handleFun HandlerFunc, filters ...string) error {
	// 校验
	if _, ok := t.tree[method]; !ok {
		fmt.Println("路由注册失败，非法的请求方式")
		return ErrorInvalidMethod
	}

	node := t.tree[method]

	paths, ok := ValidateURL(pattern)

	if !ok {
		fmt.Println("路由注册失败，URL校验失败")
		return ErrorInvalidRouterpath
	}

	// 开始判断与插入，遍历传入的路径 -- 这里会调用node的match方法
	for i, p := range paths {
		child, ok := node.FindChildNode(p, nil)

		// 原本这里的if else是反过来的，结果注册路由的时候出了bug：
		// 先注册了hello/* 之后没有办法注册 hello/:id
		// 将逻辑调整一下就可以
		if ok && child.(*treenode).nodeType != nodeTypeAny {
			// != nodeTypeAny 是考虑到 /order/* 和 /order/:id 这种注册顺序
			node = child
		} else {
			newnode, _ := node.NewChildren(paths[i:], handleFun)
			f := nodeWithFilter(handleFun, filters...)
			newnode.(*treenode).handler = HandlerFunc(f)

			return nil // 直接可以返回
		}
	}

	// 路径存在，并且处理函数也存在（重复注册时）,这里的策略是直接覆盖
	node.(*treenode).handler = nodeWithFilter(handleFun, filters...)
	return nil
}

// 建立树的时候，直接创建map[get]\map[post]\map[put]... 。这里的设计是限定住且不可以修改
// 也可以选择单例饱汉模式，需要的时候再创建 -- sync.Once
func NewTreeRouter() Handler {
	RT := &BaseOnTree{}
	RT.tree = make(map[string]BaseNode, len(httpMethod))
	for _, m := range httpMethod {
		RT.tree[m] = newRootNode(m)
	}
	return RT
}

// 校验参数 -- 在注册路由的时候调用
// 这里可以选择method url 一起校验，这个函数只校验url
func ValidateURL(pattern string) ([]string, bool) {
	// 首先校验通配符
	idx := strings.Index(pattern, "*")
	if idx > 0 { // 表示存在*
		if idx != len(pattern)-1 {
			return nil, false
		} else if pattern[idx-1] != '/' {
			return nil, false
		}
	}

	paths := strings.Split(strings.Trim(pattern, "/"), "/")
	return paths, true
}

// 将中间件与处理函数handlerfunc合并成为一条工具链
func nodeWithFilter(handleFun HandlerFunc, filters ...string) Filter {
	bNames := GetMoreFilterBuilders(filters...)

	var f Filter = handleFun

	for i := 0; i < len(bNames); i++ {
		b := bNames[i]
		f = b(f)
	}
	return f
}

// 这里表示实现成功--仅作为检验
var _ Handler = &BaseOnTree{}
